package com.mxpio.erp.quality.service.impl;

import com.mxpio.erp.common.LotStatusUtil;
import com.mxpio.erp.common.enums.InspectionEnums;
import com.mxpio.erp.common.enums.NoticeStatusEnums;
import com.mxpio.erp.common.enums.OrderEnums;
import com.mxpio.erp.common.enums.OrderStatusEnums;
import com.mxpio.erp.common.inventory.entity.*;
import com.mxpio.erp.common.inventory.service.LotService;
import com.mxpio.erp.common.jpa.model.Order;
import com.mxpio.erp.common.quality.entity.*;
import com.mxpio.erp.common.quality.service.UnqualifiedDisposalService;
import com.mxpio.erp.common.technology.entity.Item;
import com.mxpio.erp.common.vo.UnqualifiedDisposalAuditVO;
import com.mxpio.erp.common.workshop.entity.ManufactureOrder;
import com.mxpio.erp.common.workshop.entity.ManufactureOrderItem;
import com.mxpio.erp.common.workshop.entity.OutsourceOrder;
import com.mxpio.erp.common.workshop.entity.OutsourceOrderItem;
import com.mxpioframework.common.exception.MBootException;
import com.mxpioframework.common.vo.Result;
import com.mxpioframework.jpa.JpaUtil;
import com.mxpioframework.jpa.lin.Linu;
import com.mxpioframework.jpa.policy.CrudContext;
import com.mxpioframework.jpa.policy.impl.SmartCrudPolicyAdapter;
import com.mxpioframework.jpa.query.Criteria;
import com.mxpioframework.security.util.SecurityUtils;
import com.mxpioframework.system.service.impl.BaseServiceImpl;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

@Service
public class UnqualifiedDisposalServiceImpl extends BaseServiceImpl<UnqualifiedDisposal> implements UnqualifiedDisposalService {
    @Autowired
    private LotService lotService;

    @Override
    @Transactional
    public Result<UnqualifiedDisposal> audit(UnqualifiedDisposalAuditVO auditVO) {
        String bizNo = auditVO.getBizNo();
        UnqualifiedDisposal byId = this.getById(UnqualifiedDisposal.class, bizNo);
        if (byId==null){
            return Result.error("入参对象中的bizNo无效");
        }else if (byId.getBpmnStatus().equals(OrderStatusEnums.BpmnStatus.CLOSED.getStatusCode())){
            return Result.error("单据已关闭，无法审核！");
        }else if (auditVO.getAuditType().equals("3")&&(StringUtils.isBlank(byId.getTechOpinion())||StringUtils.isBlank(byId.getCraftOpinion()))){
            return Result.error("质检审核之前，需要工艺和技术审核！");
        }
        String auditType = auditVO.getAuditType();
        String opinion = auditVO.getOpinion();
        if (StringUtils.equals(auditType,"1")){//技术审核
            byId.setTechOpinion(auditVO.getOpinion());
            byId.setTechOpinionDesc(auditVO.getOpinionDesc());
            byId.setTechReviewer(SecurityUtils.getLoginUsername());
            byId.setTechReviewTime(new Date());
            if (opinion.equals("03")){//01,同意，03驳回，02不同意
                byId.setBpmnStatus(OrderStatusEnums.BpmnStatus.CREATE.getStatusCode());
            }else if (opinion.equals("02")){//01,同意，03驳回，02不同意
                byId.setBpmnStatus(OrderStatusEnums.BpmnStatus.CLOSED.getStatusCode());
            }
        }else if (StringUtils.equals(auditType,"2")){//工艺审核
            byId.setCraftOpinion(auditVO.getOpinion());
            byId.setCraftOpinionDesc(auditVO.getOpinionDesc());
            byId.setCraftReviewer(SecurityUtils.getLoginUsername());
            byId.setCraftReviewTime(new Date());
            if (opinion.equals("03")){//01,同意，03驳回，02不同意
                byId.setBpmnStatus(OrderStatusEnums.BpmnStatus.CREATE.getStatusCode());
            }else if (opinion.equals("02")){//01,同意，03驳回，02不同意
                byId.setBpmnStatus(OrderStatusEnums.BpmnStatus.CLOSED.getStatusCode());
            }
        }else if (StringUtils.equals(auditType,"3")){//质检审核
            byId.setQualityOpinion(auditVO.getOpinion());
            byId.setQualityOpinionDesc(auditVO.getOpinionDesc());
            byId.setQualityReviewer(SecurityUtils.getLoginUsername());
            byId.setQualityReviewTime(new Date());
            if (opinion.equals("03")){//01,同意，03驳回，02不同意
                byId.setBpmnStatus(OrderStatusEnums.BpmnStatus.CREATE.getStatusCode());
            }else if (opinion.equals("02")){//01,同意，03驳回，02不同意
                byId.setBpmnStatus(OrderStatusEnums.BpmnStatus.CLOSED.getStatusCode());
            }else{
                byId.setBpmnStatus(OrderStatusEnums.BpmnStatus.AUDITED.getStatusCode());//审核通过
            }
            //审核同意
            if (opinion.equals("01")){//质检同意
                List<UnqualifiedDisposalLine> lines = JpaUtil.linq(UnqualifiedDisposalLine.class).collect("bizNo", InspectionBill.class , "inspectionBillNo").equal("bizNo", bizNo).list();
                //质检单来源单类型，1采购验收，2生产验收，3委外验收  InspectionEnums

                List<UnqualifiedDisposalLine> recList = new ArrayList<>();//让步接收
                List<UnqualifiedDisposalLine> moRewList = new ArrayList<>();//生产返工
                List<UnqualifiedDisposalLine> ooRewList = new ArrayList<>();//委外返工
                List<UnqualifiedDisposalLine> scrList = new ArrayList<>();//报废

                for (UnqualifiedDisposalLine line:lines){
                    InspectionBill inspectionBill = line.getInspectionBill();
                    if (inspectionBill==null){
                        throw new MBootException("未正常关联到质检单！");
                    }
                    String applyDecision = line.getApplyDecision();//申请决策
                    if (inspectionBill.getOriginBizType().equals(InspectionEnums.OriginBizType.PURCH.getCode())){//采购
                        if (applyDecision.equals(InspectionEnums.UsageDecision.REC.getCode())){//让步接收
                            handleRec(line);
                        }else if (applyDecision.equals(InspectionEnums.UsageDecision.REJ.getCode())){//判退 不处理
                            //判退时，不处理
                            handleRej(line);
                        }else{
                            throw new MBootException("采购业务单仅支持让步接收和判退两种使用决策！");
                        }
                    }else if (inspectionBill.getOriginBizType().equals(InspectionEnums.OriginBizType.MANF.getCode())){//生产
                        if (applyDecision.equals(InspectionEnums.UsageDecision.REC.getCode())){//让步接收
                            handleRec(line);
                        }else if (applyDecision.equals(InspectionEnums.UsageDecision.REW.getCode())){//返工
                            moRewList.add(line);
                        }else if (applyDecision.equals(InspectionEnums.UsageDecision.SCR.getCode())){//报废
                            scrList.add(line);
                        }else if (applyDecision.equals(InspectionEnums.UsageDecision.REF.getCode())){//返修
                            //todo 返修逻辑暂不处理
                        }else{
                            throw new MBootException("生产业务单不支持的使用决策！");
                        }
                    }else if (inspectionBill.getOriginBizType().equals(InspectionEnums.OriginBizType.OUTS.getCode())){//委外
                        if (applyDecision.equals(InspectionEnums.UsageDecision.REC.getCode())){//让步接收
                            handleRec(line);
                        }else if (applyDecision.equals(InspectionEnums.UsageDecision.REW.getCode())){//返工
                            ooRewList.add(line);
                        }else if (applyDecision.equals(InspectionEnums.UsageDecision.SCR.getCode())){//报废
                            scrList.add(line);
                        }else if (applyDecision.equals(InspectionEnums.UsageDecision.REF.getCode())){//返修
                            //todo 返修逻辑暂不处理
                        }else{
                            throw new MBootException("委外业务单不支持的使用决策！");
                        }
                    }else if (inspectionBill.getOriginBizType().equals(InspectionEnums.OriginBizType.INVENTORY.getCode())){//库存质检
                        if (applyDecision.equals(InspectionEnums.UsageDecision.REC.getCode())){//让步接收
                            handleRec(line);
                        }else if (applyDecision.equals(InspectionEnums.UsageDecision.SCR.getCode())){//报废
                            scrList.add(line);
                        }else{
                            throw new MBootException("库存质检业务单仅支持让步接收和报废两种使用决策！");
                        }
                    }else if (inspectionBill.getOriginBizType().equals(InspectionEnums.OriginBizType.SALERE.getCode())){//销售退货
                        if (applyDecision.equals(InspectionEnums.UsageDecision.REC.getCode())){//让步接收
                            handleRec(line);
                        }else if (applyDecision.equals(InspectionEnums.UsageDecision.REJ.getCode())){//判退 不处理
                            //判退时，不处理
                            handleRej(line);
                        }else{
                            throw new MBootException("销售退货业务单仅支持让步接收和判退两种使用决策！");
                        }
                    }else{
                        throw new MBootException("质检单业务类型有误！");//实际业务不会走到该逻辑
                    }
                }
                if (moRewList.size()>0){//处理生产返工订单
                    Map<String, List<UnqualifiedDisposalLine>> origBizNoMap = moRewList.stream().collect(Collectors.groupingBy(l -> l.getInspectionBill().getOriginBizNo()));
                    for (String origBizNo :origBizNoMap.keySet()){
                        handleRew(origBizNoMap.get(origBizNo));
                    }
                }
                if (ooRewList.size()>0){//委外返工订单
                    Map<String, List<UnqualifiedDisposalLine>> origBizNoMap = ooRewList.stream().collect(Collectors.groupingBy(l -> l.getInspectionBill().getOriginBizNo()));
                    for (String origBizNo :origBizNoMap.keySet()){
                        handleRew(origBizNoMap.get(origBizNo));
                    }
                }
                if (scrList.size()>0){
                    handleScr(scrList);
                }
            }
        }
        JpaUtil.update(byId);//更新数据
        return Result.OK(byId);
    }

    @Override
    @Transactional
    public Result<UnqualifiedDisposal> saveWithCheck(UnqualifiedDisposal disposal) {
        this.save(disposal,new SmartCrudPolicyAdapter(){
            @Override
            public boolean beforeInsert(CrudContext context) {
                Object o = context.getEntity();
                if(o instanceof UnqualifiedDisposalLine){
                    UnqualifiedDisposal scrapOutApply = context.getParent();
                    ((UnqualifiedDisposalLine) o).setBizNo(scrapOutApply.getBizNo());
                }
                return true;
            }
        });
        List<UnqualifiedDisposalLine> lineList = JpaUtil.linq(UnqualifiedDisposalLine.class).collect("bizNo", InspectionBill.class, "inspectionBillNo").equal("bizNo", disposal.getBizNo()).list();
        if (lineList.isEmpty()){
            throw new MBootException("请添加明细行！");//由于先执行了save事务保存，此处需要抛出异常回滚，而非return Result.error
        }
        for (UnqualifiedDisposalLine line:lineList){
            String applyDecision = line.getApplyDecision();
            InspectionBill inspectionBill = line.getInspectionBill();
            if (StringUtils.equals(InspectionEnums.OriginBizType.PURCH.getCode(),inspectionBill.getOriginBizType())
                    ||StringUtils.equals(InspectionEnums.OriginBizType.SALERE.getCode(),inspectionBill.getOriginBizType())){
                if (!StringUtils.equals(applyDecision,InspectionEnums.UsageDecision.REC.getCode())&&
                        !StringUtils.equals(applyDecision,InspectionEnums.UsageDecision.REJ.getCode())){
                    throw new MBootException("仅支持让步接收和判退两种使用决策！");
                }
            }else if (StringUtils.equals(InspectionEnums.OriginBizType.MANF.getCode(),inspectionBill.getOriginBizType())
                    ||StringUtils.equals(InspectionEnums.OriginBizType.OUTS.getCode(),inspectionBill.getOriginBizType())){
                if (!StringUtils.equals(applyDecision,InspectionEnums.UsageDecision.REC.getCode())&&
                        !StringUtils.equals(applyDecision,InspectionEnums.UsageDecision.REW.getCode())&&
                        !StringUtils.equals(applyDecision,InspectionEnums.UsageDecision.SCR.getCode())&&
                        !StringUtils.equals(applyDecision,InspectionEnums.UsageDecision.REF.getCode())){
                    throw new MBootException("仅支持让步接收、返工、报废、返修使用决策！");
                }
            }else if (StringUtils.equals(InspectionEnums.OriginBizType.INVENTORY.getCode(),inspectionBill.getOriginBizType())){
                if (!StringUtils.equals(applyDecision,InspectionEnums.UsageDecision.REC.getCode())&&
                        !StringUtils.equals(applyDecision,InspectionEnums.UsageDecision.SCR.getCode())){
                    throw new MBootException("仅支持让步接收和报废两种使用决策！");
                }
            }
        }
        Map<String, List<UnqualifiedDisposalLine>> collect = lineList.stream().collect(Collectors.groupingBy(l -> l.getInspectionBill() + l.getApplyDecision()));
        for (String key :collect.keySet()){
            List<UnqualifiedDisposalLine> unqualifiedDisposalLines = collect.get(key);
            if (unqualifiedDisposalLines.size()>1){
                throw new MBootException("重复的使用决策！");
            }
        }
        return Result.OK(disposal);
    }

    @Override
    @Transactional
    public void handleRec(UnqualifiedDisposalLine line){
        this.lotSplitByApplyDecision(line);
        /*InspectionBill inspectionBill = line.getInspectionBill();
        //不合并让步接收对应flow出入的仓单，单条数据一仓单一明细
        //不合格品批 转出仓单
        WarehouseOrder outWo = new WarehouseOrder();
        outWo.setAccessType(OrderEnums.AccessType.OUT.getCode());
        outWo.setBpmnStatus(OrderStatusEnums.BpmnStatus.AUDITED.getStatusCode());
        outWo.setCloseStatus(OrderStatusEnums.CloseStatus.OPEN.getStatusCode());
        outWo.setOrderStatus(OrderStatusEnums.OrderStatus.FINISHED.getStatusCode());
        outWo.setOrderDate(new Date());
        outWo.setOriginBizNo(inspectionBill.getOriginBizNo());
        outWo.setWhCode(line.getWhCode());
        outWo.setWoType(NoticeStatusEnums.NoticeType.QO_OUT.getCode());//50 让步接收出
        outWo.setOriginNoticeNo(inspectionBill.getOriginNoticeNo());//关联noticeno字段
        JpaUtil.save(outWo);
        WarehouseOrderLine outWoLine = new WarehouseOrderLine();
        outWoLine.setCloseStatus(OrderStatusEnums.CloseStatus.OPEN.getStatusCode());
        Item item = JpaUtil.linq(Item.class).idEqual(inspectionBill.getItemCode()).findOne();
        if (item!=null){
            outWoLine.setItemCode(item.getItemCode());
            outWoLine.setItemGroupCode(item.getItemGroupCode());
            outWoLine.setItemName(item.getItemName());
            outWoLine.setItemSpec(item.getItemSpec());
            outWoLine.setUnitCode(item.getUnitCode());
            outWoLine.setDrawingNo(item.getDrawingNo());
        }
        outWoLine.setQuantity(line.getApplyQuantity());//申请数量
        outWoLine.setBizNo(outWo.getBizNo());
        outWoLine.setLineNo("1");
        outWoLine.setOriginBizNo(inspectionBill.getOriginBizNo());
        outWoLine.setOriginBizLineNo(inspectionBill.getOriginBizLineNo());
        outWoLine.setSort("1");

        outWoLine.setLotNo(line.getLotNo());
        outWoLine.setSubLotIndex(line.getSubLotIndex());
        outWoLine.setOriginNoticeNo(inspectionBill.getOriginNoticeNo());
        outWoLine.setOriginNoticeLineNo(inspectionBill.getOriginNoticeLineNo());
        JpaUtil.save(outWoLine);


        //不合格品批 让步接收转入仓单
        WarehouseOrder inWo = new WarehouseOrder();
        inWo.setAccessType(OrderEnums.AccessType.IN.getCode());
        inWo.setBpmnStatus(OrderStatusEnums.BpmnStatus.AUDITED.getStatusCode());
        inWo.setCloseStatus(OrderStatusEnums.CloseStatus.OPEN.getStatusCode());
        inWo.setOrderStatus(OrderStatusEnums.OrderStatus.FINISHED.getStatusCode());
        inWo.setOrderDate(new Date());
        inWo.setOriginBizNo(inspectionBill.getOriginBizNo());
        String originBizType = inspectionBill.getOriginBizType();//关联上游验收单，获取需要正常入库的仓库
        if (originBizType.equals(InspectionEnums.OriginBizType.PURCH.getCode())){
            InQualityOrder inQualityOrder = JpaUtil.getOne(InQualityOrder.class, inspectionBill.getOriginNoticeNo());
            inWo.setWhCode(inQualityOrder.getWhCode());//
        }else if (originBizType.equals(InspectionEnums.OriginBizType.MANF.getCode())){
            MoInQualityOrder moInQualityOrder = JpaUtil.getOne(MoInQualityOrder.class, inspectionBill.getOriginNoticeNo());
            inWo.setWhCode(moInQualityOrder.getWhCode());//
        }else if (originBizType.equals(InspectionEnums.OriginBizType.OUTS.getCode())){
            OoInQualityOrder ooInQualityOrder = JpaUtil.getOne(OoInQualityOrder.class, inspectionBill.getOriginNoticeNo());
            inWo.setWhCode(ooInQualityOrder.getWhCode());//
        }

        inWo.setWoType(NoticeStatusEnums.NoticeType.QO_IN.getCode());//50 让步接收出
        inWo.setOriginNoticeNo(inspectionBill.getOriginNoticeNo());//关联noticeno字段
        JpaUtil.save(inWo);
        WarehouseOrderLine inWoLine = new WarehouseOrderLine();
        inWoLine.setCloseStatus(OrderStatusEnums.CloseStatus.OPEN.getStatusCode());
        //Item item = JpaUtil.linq(Item.class).idEqual(inspectionBill.getItemCode()).findOne();
        if (item!=null){
            inWoLine.setItemCode(item.getItemCode());
            inWoLine.setItemGroupCode(item.getItemGroupCode());
            inWoLine.setItemName(item.getItemName());
            inWoLine.setItemSpec(item.getItemSpec());
            inWoLine.setUnitCode(item.getUnitCode());
            inWoLine.setDrawingNo(item.getDrawingNo());
        }
        inWoLine.setQuantity(line.getApplyQuantity());//申请数量
        inWoLine.setBizNo(inWo.getBizNo());
        inWoLine.setLineNo("1");
        inWoLine.setOriginBizNo(inspectionBill.getOriginBizNo());
        inWoLine.setOriginBizLineNo(inspectionBill.getOriginBizLineNo());
        inWoLine.setSort("1");

        //拆批
        //记录新批次号
        Lot lot = new Lot();
        lot.setLotNo(line.getLotNo());
        lot.setSubLotIndex(lotService.getCountByLotNo(line.getLotNo()).toString());//索引
        lot.setLotStatus(LotStatusUtil.toBinaryString("0"));
        //lot.setInspectionBillNo(inspectionBill.getBizNo());//不合格品批次生成时记录对应的质检单单号 溯源
        JpaUtil.save(lot);

        inWoLine.setLotNo(lot.getLotNo());
        inWoLine.setSubLotIndex(lot.getSubLotIndex());//新批次
        inWoLine.setOriginNoticeNo(inspectionBill.getOriginNoticeNo());
        inWoLine.setOriginNoticeLineNo(inspectionBill.getOriginNoticeLineNo());
        JpaUtil.save(inWoLine);

        //出流水
        InvFlow outFlow = new InvFlow();
        outFlow.setAccessType(outWo.getAccessType());
        outFlow.setItemCode(outWoLine.getItemCode());
        outFlow.setWhCode(outWo.getWhCode());
        outFlow.setQuantity(outWoLine.getQuantity());
        outFlow.setMemo(outWo.getMemo());
        outFlow.setOriginBizNo(outWo.getOriginBizNo());
        outFlow.setOriginBizType(outWo.getOriginBizType());
        outFlow.setOriginBizLineNo(outWoLine.getOriginBizLineNo());
        outFlow.setWoBizNo(outWo.getBizNo());
        outFlow.setWoBizType(outWo.getWoType());
        outFlow.setWoBizLineNo(outWoLine.getLineNo());
        outFlow.setLotNo(outWoLine.getLotNo());
        outFlow.setSubLotIndex(outWoLine.getSubLotIndex());//增加子批索引
        JpaUtil.save(outFlow);

        //入
        InvFlow inFlow = new InvFlow();
        inFlow.setAccessType(inWo.getAccessType());
        inFlow.setItemCode(inWoLine.getItemCode());
        inFlow.setWhCode(inWo.getWhCode());
        inFlow.setQuantity(inWoLine.getQuantity());
        inFlow.setMemo(inWo.getMemo());
        inFlow.setOriginBizNo(inWo.getOriginBizNo());
        inFlow.setOriginBizType(inWo.getOriginBizType());
        inFlow.setOriginBizLineNo(inWoLine.getOriginBizLineNo());
        inFlow.setWoBizNo(inWo.getBizNo());
        inFlow.setWoBizType(inWo.getWoType());
        inFlow.setWoBizLineNo(inWoLine.getLineNo());
        inFlow.setLotNo(inWoLine.getLotNo());
        inFlow.setSubLotIndex(inWoLine.getSubLotIndex());//增加子批索引
        JpaUtil.save(inFlow);
        //回写让步接收数量(质检单)
        JpaUtil.linu(InspectionBill.class).equal("bizNo",inspectionBill.getBizNo()).set("concessionQuantity",inFlow.getQuantity()).update();
        //回写让步接收数量(验收单)
        Linu linu = null;
        if (originBizType.equals(InspectionEnums.OriginBizType.PURCH.getCode())){
            linu = JpaUtil.linu(InQualityOrderLine.class);
        }else if (originBizType.equals(InspectionEnums.OriginBizType.MANF.getCode())){
            linu = JpaUtil.linu(MoInQualityOrderLine.class);
        }else if (originBizType.equals(InspectionEnums.OriginBizType.OUTS.getCode())){
            linu = JpaUtil.linu(OoInQualityOrderLine.class);
        }

        if (linu!=null){//更新验收单明细行对应的让步=接收数量
            linu.equal("noticeNo",inspectionBill.getOriginNoticeNo())
                    .equal("lineNo",inspectionBill.getOriginNoticeLineNo())
                    .set("concessionQuantity",inFlow.getQuantity()).update();
        }*/

    }
    @Override
    @Transactional
    public void handleRej(UnqualifiedDisposalLine line){
        InspectionBill inspectionBill = line.getInspectionBill();
        //回写判断数量
        JpaUtil.linu(InspectionBill.class).equal("bizNo",inspectionBill.getBizNo()).set("refundQuantity",line.getApplyQuantity()).update();
    }
    @Override
    @Transactional//返工
    public void handleRew(List<UnqualifiedDisposalLine> lines){
        InspectionBill inspectionBill = lines.get(0).getInspectionBill();
        if (inspectionBill.getOriginBizType().equals(InspectionEnums.OriginBizType.MANF.getCode())){//生产
            String originBizNo = inspectionBill.getOriginBizNo();
            ManufactureOrder mOrder = JpaUtil.getOne(ManufactureOrder.class, originBizNo);

            ManufactureOrder newMOrder = new ManufactureOrder();
            newMOrder.setCloseStatus(mOrder.getCloseStatus());
            newMOrder.setEndDate(mOrder.getEndDate());
            newMOrder.setMainWorkshop(mOrder.getMainWorkshop());
            newMOrder.setMemo(mOrder.getMemo());
            newMOrder.setOrderDate(mOrder.getOrderDate());
            newMOrder.setOrderQuantity(mOrder.getOrderQuantity());
            newMOrder.setOrderStatus(OrderStatusEnums.OrderStatus.PLAN.getStatusCode());//计划
            newMOrder.setOrderType("03");//
            newMOrder.setPlanner(mOrder.getPlanner());
            newMOrder.setProductDrawingNo(mOrder.getProductDrawingNo());
            newMOrder.setProductItemCode(mOrder.getProductItemCode());
            newMOrder.setProductItemName(mOrder.getProductItemName());
            newMOrder.setItemSpec(mOrder.getItemSpec());
            newMOrder.setReferenceDate(mOrder.getReferenceDate());
            newMOrder.setStartDate(mOrder.getStartDate());
            newMOrder.setUnitCode(mOrder.getUnitCode());
            newMOrder.setWorkCenterCode(mOrder.getWorkCenterCode());
            JpaUtil.save(newMOrder);//保存
            int lineno = 0;
            for (UnqualifiedDisposalLine line:lines){
                lotSplitByApplyDecision(line);//拆分原不合格批
                lineno++;
                InspectionBill lineInspectionBill = line.getInspectionBill();
                ManufactureOrderItem moi = new ManufactureOrderItem();
                moi.setBizNo(newMOrder.getBizNo());
                moi.setLineNo(lineno+"");
                moi.setDrawingNo(lineInspectionBill.getDrawingNo());
                moi.setItemCode(lineInspectionBill.getItemCode());
                moi.setItemName(lineInspectionBill.getItemName());
                moi.setItemSpec(lineInspectionBill.getItemSpec());
                moi.setLotNo(line.getSplitNewLotNo());
                moi.setSubLotIndex(line.getSplitNewSubLotIndex());
                moi.setWhCode(line.getSplitNewWhCode());
                moi.setUnitCode(lineInspectionBill.getUnitCode());
                moi.setQuantity(line.getApplyQuantity());
                JpaUtil.save(moi);
            }
        }else if (inspectionBill.getOriginBizType().equals(InspectionEnums.OriginBizType.OUTS.getCode())){//委外
            String originBizNo = inspectionBill.getOriginBizNo();
            OutsourceOrder oOrder = JpaUtil.getOne(OutsourceOrder.class, originBizNo);

            OutsourceOrder newOOrder = new OutsourceOrder();
            newOOrder.setBizMan(oOrder.getBizMan());
            newOOrder.setCloseStatus(oOrder.getCloseStatus());
            newOOrder.setEndDate(oOrder.getEndDate());
            newOOrder.setOrderType("03");
            newOOrder.setEntrustDept(oOrder.getEntrustDept());
            newOOrder.setMachiningDrawing(oOrder.getMachiningDrawing());
            newOOrder.setMemo(oOrder.getMemo());
            newOOrder.setOrderDate(oOrder.getOrderDate());
            newOOrder.setOrderQuantity(oOrder.getOrderQuantity());
            newOOrder.setOrderStatus(OrderStatusEnums.OrderStatus.PLAN.getStatusCode());
            newOOrder.setPlanner(oOrder.getPlanner());
            newOOrder.setPnCode(oOrder.getPnCode());
            newOOrder.setPnName(oOrder.getPnName());
            newOOrder.setProductDrawingNo(oOrder.getProductDrawingNo());
            newOOrder.setProductItemCode(oOrder.getProductItemCode());
            newOOrder.setProductItemName(oOrder.getProductItemName());
            newOOrder.setReferenceDate(oOrder.getReferenceDate());
            newOOrder.setStartDate(oOrder.getStartDate());
            newOOrder.setUnitCode(oOrder.getUnitCode());
            JpaUtil.save(newOOrder);
            int lineno = 0;
            for (UnqualifiedDisposalLine line:lines){
                lotSplitByApplyDecision(line);//拆分原不合格批
                lineno++;
                InspectionBill lineInspectionBill = line.getInspectionBill();
                OutsourceOrderItem ooi = new OutsourceOrderItem();
                ooi.setBizNo(newOOrder.getBizNo());
                ooi.setLineNo(lineno+"");
                ooi.setDrawingNo(lineInspectionBill.getDrawingNo());
                ooi.setItemCode(lineInspectionBill.getItemCode());
                ooi.setItemName(lineInspectionBill.getItemName());
                ooi.setItemSpec(lineInspectionBill.getItemSpec());
              /*  ooi.setLotNo(line.getLotNo());
                ooi.setSubLotIndex(line.getSubLotIndex());
                ooi.setWhCode(line.getWhCode());*/
                ooi.setLotNo(line.getSplitNewLotNo());
                ooi.setSubLotIndex(line.getSplitNewSubLotIndex());
                ooi.setWhCode(line.getSplitNewWhCode());
                ooi.setUnitCode(lineInspectionBill.getUnitCode());
                ooi.setQuantity(line.getApplyQuantity());
                JpaUtil.save(ooi);
            }
        }else{
            throw new MBootException("无效的业务单类型");
        }
    }

    @Override
    @Transactional
    public void handleScr(List<UnqualifiedDisposalLine> lines){//处理报废
        Map<String, List<UnqualifiedDisposalLine>> whcodeGroupMap = lines.stream().collect(Collectors.groupingBy(UnqualifiedDisposalLine::getWhCode));
        for (String whcode: whcodeGroupMap.keySet()){
            ScrapOutApply apply = new ScrapOutApply();
            apply.setBpmnStatus(OrderStatusEnums.BpmnStatus.AUDITING.getStatusCode());
            apply.setCloseStatus(OrderStatusEnums.CloseStatus.OPEN.getStatusCode());
            apply.setMemo("由不良品申请单生成");
            apply.setOrderStatus(OrderStatusEnums.OrderStatus.PLAN.getStatusCode());
            apply.setWhCode(whcode);
            JpaUtil.save(apply);

            List<UnqualifiedDisposalLine> sublines = whcodeGroupMap.get(whcode);
            int lineno = 0;
            for (UnqualifiedDisposalLine line : sublines){
                //先拆批 报废申请使用拆批后的索引
                lotSplitByApplyDecision(line);//拆分原不合格批
                //UnqualifiedDisposalLine dbLine = JpaUtil.getOne(UnqualifiedDisposalLine.class, line.getId());
                lineno++;
                InspectionBill bill = line.getInspectionBill();
                ScrapOutApplyLine scrapOutApplyLine = new ScrapOutApplyLine();
                scrapOutApplyLine.setBizNo(apply.getBizNo());
                scrapOutApplyLine.setDrawingNo(bill.getDrawingNo());
                scrapOutApplyLine.setItemCode(bill.getItemCode());
                scrapOutApplyLine.setItemName(bill.getItemName());
                scrapOutApplyLine.setItemSpec(bill.getItemSpec());
                scrapOutApplyLine.setUnitCode(bill.getUnitCode());
                scrapOutApplyLine.setLineNo(lineno+"");
                scrapOutApplyLine.setLotNo(line.getSplitNewLotNo());
                scrapOutApplyLine.setSubLotIndex(line.getSplitNewSubLotIndex());
                scrapOutApplyLine.setQuantity(line.getApplyQuantity());
                scrapOutApplyLine.setScrapReason("不良品申请单处理结果:报废");
                scrapOutApplyLine.setQcStatus(line.getApplyDecision());//质检结果
                JpaUtil.save(scrapOutApplyLine);
            }

        }
    }


    @Override
    @Transactional(readOnly = true)
    public Page<VInvLotStock> lotPageUDUnRefer(Pageable pageAble, Criteria c) {//不良品批次，未被不合格品单引用的批次
        Set<String> bizNos = null;
        List<UnqualifiedDisposal> unCloseUDList = JpaUtil.linq(UnqualifiedDisposal.class).notEqual("bpmnStatus", OrderStatusEnums.BpmnStatus.CLOSED.getStatusCode()).list();
        if (unCloseUDList.size()>0){//查找非关闭不良品处理单的单号
            bizNos = unCloseUDList.stream().map(UnqualifiedDisposal::getBizNo).collect(Collectors.toSet());
        }
        if (CollectionUtils.isEmpty(bizNos)){
            return JpaUtil.linq(VInvLotStock.class)
                    .collect("bizNo", InspectionBill.class, "inspectionBillNo")
                    .like("lotStatus","_______________1").gt("quantity",0).where(c).paging(pageAble);
        }else{
            return JpaUtil.linq(VInvLotStock.class)
                    .collect("bizNo", InspectionBill.class, "inspectionBillNo")
                    .like("lotStatus","_______________1")
                    .gt("quantity",0)
                    .notExists(UnqualifiedDisposalLine.class)
                    .equalProperty("lotNo", "lotNo")
                    .equalProperty("subLotIndex", "subLotIndex")
                        .in("bizNo", bizNos)
                    .end()
                    .where(c)
                    .paging(pageAble);
        }
    }

    @Override
    @Transactional(readOnly = false)
    public Result<? extends Order> submitOrder(String bizNo) {
        UnqualifiedDisposal po = this.getById(UnqualifiedDisposal.class, bizNo);
        if (!po.getBpmnStatus().equals(OrderStatusEnums.BpmnStatus.CREATE.getStatusCode())) {
            return Result.error("非开立状态不可提交");
        }
        //提交时 ，检查 历史审核意见，并清空(处理驳回)
        if (StringUtils.isNotBlank(po.getTechOpinion())){
            po.setTechOpinion(null);
            po.setTechOpinionDesc(null);
            po.setTechReviewer(null);
            po.setTechReviewTime(null);
        }
        if (StringUtils.isNotBlank(po.getCraftOpinion())){
            po.setCraftOpinion(null);
            po.setCraftOpinionDesc(null);
            po.setCraftReviewer(null);
            po.setCraftReviewTime(null);
        }
        if (StringUtils.isNotBlank(po.getQualityOpinion())){
            po.setQualityOpinion(null);
            po.setQualityOpinionDesc(null);
            po.setQualityReviewer(null);
            po.setQualityReviewTime(null);
        }
        po.setBpmnStatus(OrderStatusEnums.BpmnStatus.AUDITING.getStatusCode());
        po.setReviewer(SecurityUtils.getLoginUsername());
        po.setReviewTime(new Date());
        return Result.OK(po);
    }

    @Override
    @Transactional//需要拆批的
    public void lotSplitByApplyDecision(UnqualifiedDisposalLine line){
        InspectionBill inspectionBill = line.getInspectionBill();
        String originBizType = inspectionBill.getOriginBizType();
        String applyDecision = line.getApplyDecision();
        //不合并让步接收对应flow出入的仓单，单条数据一仓单一明细
        //拆批，对应库存转移
        WarehouseOrder outWo = new WarehouseOrder();
        outWo.setAccessType(OrderEnums.AccessType.OUT.getCode());
        outWo.setBpmnStatus(OrderStatusEnums.BpmnStatus.AUDITED.getStatusCode());
        outWo.setCloseStatus(OrderStatusEnums.CloseStatus.OPEN.getStatusCode());
        outWo.setOrderStatus(OrderStatusEnums.OrderStatus.FINISHED.getStatusCode());
        outWo.setOrderDate(new Date());
        outWo.setOriginBizNo(inspectionBill.getOriginBizNo());
        outWo.setWhCode(line.getWhCode());
        if (StringUtils.equals(applyDecision,InspectionEnums.UsageDecision.REW.getCode())){//返工
            outWo.setWoType(NoticeStatusEnums.NoticeType.QREW_OUT.getCode());//("52", "不良品处理-返工-转移出")
        }else if (StringUtils.equals(applyDecision,InspectionEnums.UsageDecision.SCR.getCode())){//报废
            outWo.setWoType(NoticeStatusEnums.NoticeType.QSCR_OUT.getCode());//("54", "不良品处理-报废-转移出")
        }else if (StringUtils.equals(applyDecision,InspectionEnums.UsageDecision.REC.getCode())){
            outWo.setWoType(NoticeStatusEnums.NoticeType.QO_OUT.getCode());//QO_OUT("50", "质检让步接收出")
        }
        outWo.setOriginNoticeNo(inspectionBill.getOriginNoticeNo());//关联noticeno字段
        outWo.setExecuteTime(new Date());
        outWo.setExecutor("8888");//自动化助手，默认指定用户
        JpaUtil.save(outWo);
        WarehouseOrderLine outWoLine = new WarehouseOrderLine();
        outWoLine.setWhCode(outWo.getWhCode());
        outWoLine.setCloseStatus(OrderStatusEnums.CloseStatus.OPEN.getStatusCode());
        Item item = JpaUtil.linq(Item.class).idEqual(inspectionBill.getItemCode()).findOne();
        if (item!=null){
            outWoLine.setItemCode(item.getItemCode());
            outWoLine.setItemGroupCode(item.getItemGroupCode());
            outWoLine.setItemName(item.getItemName());
            outWoLine.setItemSpec(item.getItemSpec());
            outWoLine.setUnitCode(item.getUnitCode());
            outWoLine.setDrawingNo(item.getDrawingNo());
        }
        outWoLine.setQuantity(line.getApplyQuantity());//申请数量
        outWoLine.setBizNo(outWo.getBizNo());
        outWoLine.setLineNo("1");
        outWoLine.setOriginBizNo(inspectionBill.getOriginBizNo());
        outWoLine.setOriginBizLineNo(inspectionBill.getOriginBizLineNo());
        outWoLine.setSort("1");

        outWoLine.setLotNo(line.getLotNo());
        outWoLine.setSubLotIndex(line.getSubLotIndex());
        outWoLine.setOriginNoticeNo(inspectionBill.getOriginNoticeNo());
        outWoLine.setOriginNoticeLineNo(inspectionBill.getOriginNoticeLineNo());
        JpaUtil.save(outWoLine);


        //不合格品批 让步接收转入仓单
        WarehouseOrder inWo = new WarehouseOrder();
        inWo.setAccessType(OrderEnums.AccessType.IN.getCode());
        inWo.setBpmnStatus(OrderStatusEnums.BpmnStatus.AUDITED.getStatusCode());
        inWo.setCloseStatus(OrderStatusEnums.CloseStatus.OPEN.getStatusCode());
        inWo.setOrderStatus(OrderStatusEnums.OrderStatus.FINISHED.getStatusCode());
        inWo.setOrderDate(new Date());
        inWo.setOriginBizNo(inspectionBill.getOriginBizNo());

        if (StringUtils.equals(applyDecision,InspectionEnums.UsageDecision.REW.getCode())){//返工
            inWo.setWoType(NoticeStatusEnums.NoticeType.QREW_IN.getCode());//("53", "不良品处理-返工-转移入")
            //取原不合格批对应仓库
            inWo.setWhCode(line.getWhCode());
        }else if (StringUtils.equals(applyDecision,InspectionEnums.UsageDecision.SCR.getCode())){//报废
            inWo.setWoType(NoticeStatusEnums.NoticeType.QSCR_IN.getCode());//("55", "不良品处理-报废-转移入")
            //取原不合格批对应仓库
            inWo.setWhCode(line.getWhCode());
        }else if (StringUtils.equals(applyDecision,InspectionEnums.UsageDecision.REC.getCode())){
            inWo.setWoType(NoticeStatusEnums.NoticeType.QO_IN.getCode());//QO_IN("51", "质检让步接收入"),
            //让步接收 仓库取原验收单对应仓库
            if (originBizType.equals(InspectionEnums.OriginBizType.PURCH.getCode())){
                InQualityOrder inQualityOrder = JpaUtil.getOne(InQualityOrder.class, inspectionBill.getOriginNoticeNo());
                inWo.setWhCode(inQualityOrder.getWhCode());//
            }else if (originBizType.equals(InspectionEnums.OriginBizType.MANF.getCode())){
                MoInQualityOrder moInQualityOrder = JpaUtil.getOne(MoInQualityOrder.class, inspectionBill.getOriginNoticeNo());
                inWo.setWhCode(moInQualityOrder.getWhCode());//
            }else if (originBizType.equals(InspectionEnums.OriginBizType.OUTS.getCode())){
                OoInQualityOrder ooInQualityOrder = JpaUtil.getOne(OoInQualityOrder.class, inspectionBill.getOriginNoticeNo());
                inWo.setWhCode(ooInQualityOrder.getWhCode());//
            }else if (originBizType.equals(InspectionEnums.OriginBizType.INVENTORY.getCode())){
                InventoryQualityOrder inventoryQualityOrder = JpaUtil.getOne(InventoryQualityOrder.class, inspectionBill.getOriginNoticeNo());
                inWo.setWhCode(inventoryQualityOrder.getWhCode());//
            }else if (originBizType.equals(InspectionEnums.OriginBizType.SALERE.getCode())){
                SoInQualityOrder soInQualityOrder = JpaUtil.getOne(SoInQualityOrder.class, inspectionBill.getOriginNoticeNo());
                inWo.setWhCode(soInQualityOrder.getWhCode());//
            }
        }else{
            throw new MBootException("无效的申请使用决策");
        }
        inWo.setOriginNoticeNo(inspectionBill.getOriginNoticeNo());//关联noticeno字段
        inWo.setExecuteTime(new Date());
        inWo.setExecutor("8888");//自动化助手，默认指定用户
        JpaUtil.save(inWo);
        WarehouseOrderLine inWoLine = new WarehouseOrderLine();
        inWoLine.setWhCode(inWo.getWhCode());
        inWoLine.setCloseStatus(OrderStatusEnums.CloseStatus.OPEN.getStatusCode());
        if (item!=null){
            inWoLine.setItemCode(item.getItemCode());
            inWoLine.setItemGroupCode(item.getItemGroupCode());
            inWoLine.setItemName(item.getItemName());
            inWoLine.setItemSpec(item.getItemSpec());
            inWoLine.setUnitCode(item.getUnitCode());
            inWoLine.setDrawingNo(item.getDrawingNo());
        }
        inWoLine.setQuantity(line.getApplyQuantity());//申请数量
        inWoLine.setBizNo(inWo.getBizNo());
        inWoLine.setLineNo("1");
        inWoLine.setOriginBizNo(inspectionBill.getOriginBizNo());
        inWoLine.setOriginBizLineNo(inspectionBill.getOriginBizLineNo());
        inWoLine.setSort("1");

        //拆批
        //记录新批次号
        Lot lot = new Lot();
        lot.setLotNo(line.getLotNo());
        lot.setSubLotIndex(lotService.getCountByLotNo(line.getLotNo()).toString());//索引
        if (StringUtils.equals(applyDecision,InspectionEnums.UsageDecision.REC.getCode())){
            lot.setLotStatus(LotStatusUtil.toBinaryString("0"));//让步接收改为正常
        }else{
            String binaryString = LotStatusUtil.toBinaryString("0");//默认正常
            lot.setLotStatus(LotStatusUtil.switchBinaryByIndex(binaryString,InspectionEnums.LotStatusBitIndex.IB15.getIndex()));//和源批状态保持一致
        }
        lot.setInspectionBillNo(inspectionBill.getBizNo());//不合格品批次生成时记录对应的质检单单号 溯源
        JpaUtil.save(lot);

        inWoLine.setLotNo(lot.getLotNo());
        inWoLine.setSubLotIndex(lot.getSubLotIndex());//新批次
        inWoLine.setOriginNoticeNo(inspectionBill.getOriginNoticeNo());
        inWoLine.setOriginNoticeLineNo(inspectionBill.getOriginNoticeLineNo());
        JpaUtil.save(inWoLine);

        //出流水
        InvFlow outFlow = new InvFlow();
        outFlow.setAccessType(outWo.getAccessType());
        outFlow.setItemCode(outWoLine.getItemCode());
        outFlow.setWhCode(outWo.getWhCode());
        outFlow.setQuantity(outWoLine.getQuantity());
        outFlow.setMemo(outWo.getMemo());
        outFlow.setOriginBizNo(outWo.getOriginBizNo());
        outFlow.setOriginBizType(outWo.getOriginBizType());
        outFlow.setOriginBizLineNo(outWoLine.getOriginBizLineNo());
        outFlow.setWoBizNo(outWo.getBizNo());
        outFlow.setWoBizType(outWo.getWoType());
        outFlow.setWoBizLineNo(outWoLine.getLineNo());
        outFlow.setLotNo(outWoLine.getLotNo());
        outFlow.setSubLotIndex(outWoLine.getSubLotIndex());//增加子批索引
        JpaUtil.save(outFlow);

        //入
        InvFlow inFlow = new InvFlow();
        inFlow.setAccessType(inWo.getAccessType());
        inFlow.setItemCode(inWoLine.getItemCode());
        inFlow.setWhCode(inWo.getWhCode());
        inFlow.setQuantity(inWoLine.getQuantity());
        inFlow.setMemo(inWo.getMemo());
        inFlow.setOriginBizNo(inWo.getOriginBizNo());
        inFlow.setOriginBizType(inWo.getOriginBizType());
        inFlow.setOriginBizLineNo(inWoLine.getOriginBizLineNo());
        inFlow.setWoBizNo(inWo.getBizNo());
        inFlow.setWoBizType(inWo.getWoType());
        inFlow.setWoBizLineNo(inWoLine.getLineNo());
        inFlow.setLotNo(inWoLine.getLotNo());
        inFlow.setSubLotIndex(inWoLine.getSubLotIndex());//增加子批索引
        JpaUtil.save(inFlow);

        if (StringUtils.equals(applyDecision,InspectionEnums.UsageDecision.REC.getCode())){
            //回写让步接收数量(质检单)
            JpaUtil.linu(InspectionBill.class).equal("bizNo",inspectionBill.getBizNo()).set("concessionQuantity",inFlow.getQuantity()).update();
            //回写让步接收数量(验收单)
            Linu linu = null;
            if (originBizType.equals(InspectionEnums.OriginBizType.PURCH.getCode())){
                linu = JpaUtil.linu(InQualityOrderLine.class);
            }else if (originBizType.equals(InspectionEnums.OriginBizType.MANF.getCode())){
                linu = JpaUtil.linu(MoInQualityOrderLine.class);
            }else if (originBizType.equals(InspectionEnums.OriginBizType.OUTS.getCode())){
                linu = JpaUtil.linu(OoInQualityOrderLine.class);
            }

            if (linu!=null){//更新验收单明细行对应的让步=接收数量
                linu.equal("noticeNo",inspectionBill.getOriginNoticeNo())
                        .equal("lineNo",inspectionBill.getOriginNoticeLineNo())
                        .set("concessionQuantity",inFlow.getQuantity()).update();
            }
        }
        line.setSplitNewLotNo(inFlow.getLotNo());
        line.setSplitNewSubLotIndex(inFlow.getSubLotIndex());
        line.setSplitNewWhCode(inFlow.getWhCode());//供下游生成报废申请单使用
        //不良品明细行回写新拆批信息
        JpaUtil.linu(UnqualifiedDisposalLine.class).equal("id",line.getId())
                .set("splitNewWhCode",inFlow.getWhCode())
                .set("splitNewLotNo",inFlow.getLotNo())
                .set("splitNewSubLotIndex",inFlow.getSubLotIndex())
                .update();
    }
}

